package znet

import (
	"errors"
	"fmt"
	"gitee.com/MrDaiM/zinx/utils"
	"gitee.com/MrDaiM/zinx/ziface"
	"net"
	"time"

)

//Server IServer 接口实现 定义一个Server服务器
type Server struct {
	// 服务器的名称
	Name string
	// TCP or Other
	IPVersion string
	// 服务器绑定的IP地址
	IP string
	// 服务器绑定的端口
	Port int
	// 当前Server有用户绑定的回调router，也就是Server注册的连接对应的处理业务
	//Router ziface.IRouter

	// 当前Server的消息的管理模块，用来绑定MsgId和对应的处理方法
	msgHandler ziface.IMsgHandle

	// 当前Server的 链接管理器
	ConnMgr ziface.IConnManager


	// =======
	// 新增两个hooK函数原型

	// 该Server的连接创建时Hook函数
	OnConnStart func(conn ziface.IConnection)
	// 该Server的链接断开时的Hook函数
	OnConnStop func(conn ziface.IConnection)

	// ========



}

func NewServer() ziface.IServer {
	s := &Server{
		Name:       utils.GlobalObject.Name,
		IPVersion:  "tcp4", // 从全局加载
		IP:         utils.GlobalObject.Host,
		Port:       utils.GlobalObject.TcpPort,
		msgHandler: NewMsgHandle(), // 初始化
		ConnMgr:    NewConnManager(),
	}
	return s
}

// ====================== 定义当前客户端连接的handle api ======================

func CallBackToClient(conn *net.TCPConn, data []byte, cnt int) error {
	// 回显业务
	fmt.Println("[Conn Handle] CallBackToClient ...")
	if _, err := conn.Write(data[:cnt]); err != nil {
		fmt.Println("write back buf err ", err)

		return errors.New("CallBackToClient error")
	}
	return nil
}

// ====================== 实现ziface.IServer 里的全部接口方法 ======================

// AddRouter 路由功能: 给当前服务注册一个路由业务方法，供客户端链接处理使用
//func (s *Server)AddRouter(router ziface.IRouter) {
//	fmt.Println("Add Router success!")
//	s.Router = router
//}

func (s *Server) AddRouter(msgId uint32, router ziface.IRouter) {
	fmt.Println("Add Router success!")

	s.msgHandler.AddRouter(msgId, router)
}

// Start 开启网络服务
func (s *Server) Start() {

	fmt.Printf("[START] Server name: %s, listener at IP: %s, Port: %d is Starting\n", s.Name, s.IP, s.Port)
	fmt.Printf("[Zinx] Version: %s, MAxConnt: %d, MaxPacketSize: %d\n",
		utils.GlobalObject.Version,
		utils.GlobalObject.MaxCount,
		utils.GlobalObject.MaxPacketSize)

	// 开启一个go去做服务端的listener业务
	go func() {

		// 0. 启动Worker工作池机制
		s.msgHandler.StartWorkerPool()

		// 1. 获取一个TCP的Addr
		addr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))
		if err != nil {
			fmt.Println("resolve tcp addr err: ", err)
			return
		}

		// 2. 监听服务器的地址
		listener, err := net.ListenTCP(s.IPVersion, addr)
		if err != nil {
			fmt.Println("listener", s.IPVersion, "err", err)
			return
		}

		// 已经监听成功
		fmt.Println("start Zinx server  ", s.Name, "success now listening...")

		// TODO server.go 应该由一个自动生成ID的方法
		var cid uint32
		cid = 0
		// 3. 启动server网络连接业务
		for {
			// 3.1 阻塞等待客户端简历连接请求
			conn, err := listener.AcceptTCP()
			if err != nil {
				fmt.Println("Accept error:", err)
				continue
			}

			// ============
			// 3.2 Server.Start() 设置服务器最大连接控制，如果超过最大连接，那么关闭此新的连接
			if s.ConnMgr.Len() >= utils.GlobalObject.MaxConn {
				conn.Close()
				continue
			}
			// ============

			// 3.3 处理该新连接请求的 业务 方法 此时应该由 handler 和 conn 是绑定的
			dealConn := NewConnection(s, conn, cid, s.msgHandler)
			cid++

			// 3.4 启动当前连接处理业务
			go dealConn.Start()

			// V0.1版本暂时做一个最大512字节的回显服务
			//go func() {
			//	// 创建一个go程提高读取效率
			//	// 有序服务端是不断的发送
			//	// 不断的循环从客户端获取数据
			//
			//	for  {
			//		buf := make([]byte, 512)
			//		cnt, err := conn.Read(buf)
			//		if err != nil {
			//			fmt.Println("recv buf err: ", err)
			//			continue
			//		}
			//		// 回显
			//		if _, err := conn.Write(buf[:cnt]); err != nil  {
			//			fmt.Println("write back buf err: ", err)
			//			continue
			//		}
			//	}
			//
			//}()

		}

	}()

}

// Stop 停止服务
func (s *Server) Stop() {

	fmt.Println("【STOP】 Zinx server, name ", s.Name)

	// Server.Stop 将其他需要清理的连接信息或者其他信息，也要一并停止或者清理
	s.ConnMgr.ClearConn()

}

// Serve 提供给外界调用服务
func (s *Server) Serve() {
	s.Start()
	// 阻塞,否则主Go退出, listener的go将会退出
	for {
		time.Sleep(10 * time.Second)
	}
}

// GetConnMgr 得到链接管理
func (s *Server) GetConnMgr() ziface.IConnManager {
	return s.ConnMgr
}


// SetOnConnStart 设置该Server的链接创建时Hook函数
func (s *Server) SetOnConnStart( hookFunc func (connection ziface.IConnection)) {
	s.OnConnStart = hookFunc
}
// SetOnConnStop 设置该Server的连接断开时的Hook函数
func (s *Server) SetOnConnStop(hookFunc func (connection ziface.IConnection)) {
	s.OnConnStop = hookFunc
}
// CallOnConnStart 调用链接OnConnStart Hook 函数
func (s *Server) CallOnConnStart(conn ziface.IConnection) {
	if s.OnConnStart != nil {
		fmt.Println("---> CallOnConnStart")
		s.OnConnStart(conn)
	}

}
// CallOnConnStop 调用链接OnConnStop Hook函数
func (s *Server) CallOnConnStop(conn ziface.IConnection) {

	if s.OnConnStop != nil {
		fmt.Println("----> CallOnConnStop")
		s.OnConnStop(conn)
	}

}
